/***************************************************************************
 *   Copyright (C) 2009 by Geoffrey McRae   *
 *   geoff@spacevs.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "array.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

struct array {	
	unsigned int	size, used, boundry;
	void		**items;
};

inline void array_resize(array_t *a, unsigned int size) {
	a->size		= size;
	a->items	= realloc(a->items, sizeof(void*) * size);
	a->boundry	= size / 2;
	if (a->used > size) a->used = size;
}

array_t* array_new() {
	array_t *a;
	a		= malloc(sizeof(array_t));
	a->items	= NULL;
	a->used		= 0;
	array_resize(a, 10);
	return a;
}

void array_free(array_t *a) {
	free(a->items);
	free(a);
}

inline void array_empty(array_t *a) {
	a->used = 0;
	array_resize(a, 10);
}

inline void array_push(array_t *a, void* data) {
	if (a->used == a->size) array_resize(a, a->size * 2);
	a->items[a->used++] = data;
}

inline void* array_pop(array_t *a) {
	void *data;
	assert(a->used > 0);
	data = a->items[--a->used];
	if (a->used == a->boundry) array_resize(a, a->size / 1.5);
	return data;
}

inline void array_unshift(array_t *a, void *data) {
	if (a->used == a->size) array_resize(a, a->size * 2);
	memmove(&a->items[1], &a->items[0], a->used++);
	a->items[0] = data;
}

inline void* array_shift(array_t *a) {
	void *data;
	assert(a->used > 0);
	data = a->items[0];
	memmove(&a->items[0], &a->items[1], --a->used);
	if (a->used == a->boundry) array_resize(a, a->size / 1.5);
	return data;
}

inline void* array_get(array_t *a, unsigned int index) {
	assert(index >= 0);
	assert(index < a->used);
	return a->items[index];
}

inline void array_del(array_t *a, unsigned int index, unsigned int count) {
	unsigned int end;
	assert(index >= 0	);
	assert(index < a->used	);
	end = index + count;
	assert(end <= a->used	);

	memmove(&a->items[index], &a->items[end], a->used - end);
	a->used -= count;

	if (a->used == a->boundry) array_resize(a, a->size / 1.5);
}

inline void array_ins(array_t *a, unsigned int index, void* data) {
	if (a->used == a->size) array_resize(a, a->size * 2);
	memmove(&a->items[index+1], &a->items[index], a->used++ - index);
	a->items[index] = data;
}

inline unsigned int array_count(array_t *a) {
	return a->used;
}

